/************************************************************************
                                                                     
   Xceed Ultimate ListBox for Silverlight                                                                                                                                            
   Copyright (C) 2010 Xceed Software Inc.    
                                                                     
   This program is provided to you under the terms of the GNU General Public  
   License version 2 as published by the Free Software Foundation. 
        
   This program is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY, without even the implied warranty of 
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should have received a copy of the GNU General Public License along 
   with this program, if not, write to the Free Software Foundation, Inc., 
   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

   This program can be provided to you by Xceed Software Inc. under a
   proprietary commercial license agreement for use in non-Open Source
   projects. Visit Xceed.com to find the commercial edition of 
   Xceed Ultimate ListBox for Silverlight.                                    
                                                                      
 **********************************************************************/

using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;

namespace Xceed.Silverlight.ListBox
{
  // This is a hack to keep the same API
  // as ItemsControl, ItemsPresenter, and ItemsPanelTemplate,
  // but the types are not of the same base class.
  // This class is intended to be used only in the ListBox
  // ControlTemplate as the ItemsPanel placeholder.
  public sealed class ItemsPresenter : ContentControl, IScrollInfo
  {
    #region Contructors

    public ItemsPresenter()
    {
      // The ItemsPresenter itself must not be IsTabStop.
      // The control itself behaves differently than the
      // MS ListBox because we only try to have the same 
      // API. This is also the reason why we set TabNavigation
      // to Once to avoid local navigation on each Children
      // of the PanelBase that will contain every containers
      // of the ListBox.
      this.IsTabStop = false;
      this.TabNavigation = KeyboardNavigationMode.Once;
    }

    #endregion

    #region Static Fields

    private static string DefaultItemsPanelTemplateString =
      @"<sllb:ItemsPanelTemplate xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"" "
      + @"xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml"" "
      + @"xmlns:sllb=""clr-namespace:Xceed.Silverlight.ListBox;assembly=Xceed.Silverlight.ListBox.v1.3"">"
      + @"<sllb:StackPanel Orientation=""Vertical""/>"
      + @"</sllb:ItemsPanelTemplate>";

    #endregion

    #region Internal Methods

    internal void InitializeAndLoadItemsPanelTemplate()
    {
      // Get the top most Parent, meaning the root element
      // of the ControlTemplate's scrope
      FrameworkElement parent = this.Parent as FrameworkElement;

      while( parent != null )
      {
        parent = parent.Parent as FrameworkElement;

        if( parent.Parent == null )
          break;
      }

      if( parent == null )
        throw new ListBoxInternalException( "The ItemsPresenter has no parent." );

      // Use VisualTreeHelper to get the "Logical Parent" of the root element
      // which is the TemplatedParent, not directly available in Silverlight
      ListBox listBox = VisualTreeHelper.GetParent( parent ) as ListBox;

      ItemsPanelTemplate itemsPanelTemplate = null;

      if( listBox != null )
        itemsPanelTemplate = listBox.ItemsPanel;

      if( itemsPanelTemplate == null )
      {
        itemsPanelTemplate = XamlReader.Load( ItemsPresenter.DefaultItemsPanelTemplateString ) as ItemsPanelTemplate;
      }

      // Use the ItemsPanelTemplate defined on the ListBox
      // if manually defined, else use the default one
      m_panel = itemsPanelTemplate.LoadContent() as PanelBase;

      if( m_panel == null )
        throw new ListBoxException( "The ItemsPanelTemplate root element must be a class derived from PanelBase." );

      // Shortcut to forward all IScrollInfo values in the
      // local implementation to the Panel
      m_panelIScrollInfo = m_panel as IScrollInfo;

      // Affect the Content of this ContentControl
      // to the Panel, which will be the only child
      this.Content = m_panel;
    }

    #endregion

    #region Private Fields

    private PanelBase m_panel;
    private IScrollInfo m_panelIScrollInfo;

    #endregion

    #region IScrollInfo Members

    bool IScrollInfo.CanHorizontallyScroll
    {
      get
      {
        return m_panelIScrollInfo.CanHorizontallyScroll;
      }
      set
      {
        m_panelIScrollInfo.CanHorizontallyScroll = value;
      }
    }

    bool IScrollInfo.CanVerticallyScroll
    {
      get
      {
        return m_panelIScrollInfo.CanVerticallyScroll;
      }
      set
      {
        m_panelIScrollInfo.CanVerticallyScroll = value;
      }
    }

    double IScrollInfo.ExtentHeight
    {
      get
      {
        return m_panelIScrollInfo.ExtentHeight;
      }
    }

    double IScrollInfo.ExtentWidth
    {
      get
      {
        return m_panelIScrollInfo.ExtentWidth;
      }
    }

    double IScrollInfo.HorizontalOffset
    {
      get
      {
        return m_panelIScrollInfo.HorizontalOffset;
      }
    }

    void IScrollInfo.LineDown()
    {
      m_panelIScrollInfo.LineDown();
    }

    void IScrollInfo.LineLeft()
    {
      m_panelIScrollInfo.LineLeft();
    }

    void IScrollInfo.LineRight()
    {
      m_panelIScrollInfo.LineRight();
    }

    void IScrollInfo.LineUp()
    {
      m_panelIScrollInfo.LineUp();
    }

    Rect IScrollInfo.MakeVisible( UIElement visual, Rect rectangle )
    {
      return m_panelIScrollInfo.MakeVisible( visual, rectangle );
    }

    void IScrollInfo.MouseWheelDown()
    {
      m_panelIScrollInfo.MouseWheelDown();
    }

    void IScrollInfo.MouseWheelLeft()
    {
      m_panelIScrollInfo.MouseWheelLeft();
    }

    void IScrollInfo.MouseWheelRight()
    {
      m_panelIScrollInfo.MouseWheelRight();
    }

    void IScrollInfo.MouseWheelUp()
    {
      m_panelIScrollInfo.MouseWheelUp();
    }

    void IScrollInfo.PageDown()
    {
      m_panelIScrollInfo.PageDown();
    }

    void IScrollInfo.PageLeft()
    {
      m_panelIScrollInfo.PageLeft();
    }

    void IScrollInfo.PageRight()
    {
      m_panelIScrollInfo.PageRight();
    }

    void IScrollInfo.PageUp()
    {
      m_panelIScrollInfo.PageUp();
    }

    ScrollViewer IScrollInfo.ScrollOwner
    {
      get
      {
        return m_panelIScrollInfo.ScrollOwner;
      }
      set
      {
        m_panelIScrollInfo.ScrollOwner = value;
      }
    }

    void IScrollInfo.SetHorizontalOffset( double offset )
    {
      m_panelIScrollInfo.SetHorizontalOffset( offset );
    }

    void IScrollInfo.SetVerticalOffset( double offset )
    {
      m_panelIScrollInfo.SetVerticalOffset( offset );
    }

    double IScrollInfo.VerticalOffset
    {
      get
      {
        return m_panelIScrollInfo.VerticalOffset;
      }
    }

    double IScrollInfo.ViewportHeight
    {
      get
      {
        return m_panelIScrollInfo.ViewportHeight;
      }
    }

    double IScrollInfo.ViewportWidth
    {
      get
      {
        return m_panelIScrollInfo.ViewportWidth;
      }
    }

    #endregion
  }
}
